热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

负值|学号_ICS计算系统概论LC3汇编实验Lab5—中断递归解决汉诺塔问题

篇首语:本文由编程笔记#小编为大家整理,主要介绍了ICS计算系统概论LC3汇编实验Lab5—中断递归解决汉诺塔问题相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了ICS计算系统概论LC3汇编实验Lab5—中断递归解决汉诺塔问题相关的知识,希望对你有一定的参考价值。



Lab
Purpose
  1. 完成用户程序的编写。
  2. 编写下面描述的键盘中断服务例程。

condition:
用户程序:
汉诺塔的参数,记录为N,将用xFFFF初始化并存储在X3FFF内存中。 您的用户程序从 x3000 开始,将持续(即无限循环)打印您的学生证,如下所示: PB12345678 PB12345678 PB12345678 PB12345678 PB12345678 PB12345678 ······ 并等待参数 N 成为有效值。当 N 成为有效值时,程序停止等待并调用 HANOI 子例程来解决问题。HANOI 子例程解决问题后,您的结果应以十进制格式显示在控制台上。 为了确保屏幕上的输出不会太快而无法用肉眼看到,用户程序应包含一段代码,该代码将在屏幕上输出每个单词后从2500(或任何其他数字)开始倒计时
终端服务例程:
从 x1000 开始的键盘中断服务例程将检查键入的键以查看它是否为十进制数字。如果键入的字符不是十进制数字&#xff0c;中断服务例程将从屏幕上的新行开始打印“<输入字符>不是十进制数字”。然后&#xff0c;服务例程会将换行符 &#xff08;x0A&#xff09; 打印到屏幕上&#xff0c;最后以 RTI 终止。 如果键入的字符是十进制数字&#xff0c;则中断服务例程将从屏幕上的新行开始打印“是十进制数字”。然后&#xff0c;您应该将此十进制数保存到x3FFF。 例如&#xff0c;如果输入键为“K”&#xff0c;则中断服务例程将打印&#xff1a;K 不是十进制数字。如果输入键为“4”&#xff0c;则中断服务例程将打印&#xff1a;4 是十进制数字。并将 x3FFF 的值更改为 4。 然后&#xff0c;服务例程会将换行符 &#xff08;x0A&#xff09; 打印到屏幕上&#xff0c;最后以 RTI 终止。 提示&#xff1a;不要忘记保存和恢复中断服务例程中使用的任何寄存器。

several examples:


Principles

Key issues:

The user program
用户程序完成循环输出学号的功能&#xff0c;只要程序没有被中断、没有结束那么就不停的输出学号&#xff0c;并且为了让输出更慢一些&#xff0c;需要加上一个数字循环减来控制输出速度

The keyboard interrupt service routine


  • 中断程序里面完成的功能有&#xff1a;
    1. 汉诺塔的计算&#xff1a;使用递归算法解决
    2. 输入数字的判断&#xff1a;数字相减取acsii码
    3. 十进制转换acsii码&#xff1a;最多可到3位数&#xff0c;因此对个十百位都需要转换再依次输出

Procedure

实验代码使用框架完成&#xff0c;中断向量表的控制在模板中已有

.ORIG x800
; (1) Initialize interrupt vector table.
LD R0, VEC
LD R1, ISR
STR R1, R0, #0
; (2) Set bit 14 of KBSR.
LDI R0, KBSR
LD R1, MASK
NOT R1, R1
AND R0, R0, R1
NOT R1, R1
ADD R0, R0, R1
STI R0, KBSR
; (3) Set up system stack to enter user space.
LD R0, PSR
ADD R6, R6, #-1
STR R0, R6, #0
LD R0, PC
ADD R6, R6, #-1
STR R0, R6, #0
; Enter user space.
RTI

VEC .FILL x0180
ISR .FILL x1000
KBSR .FILL xFE00
MASK .FILL x4000
PSR .FILL x8002
PC .FILL x3000
.END

用户程序如下&#xff0c;使用LEA取字符串至寄存器中&#xff0c;再使用PUTS输出&#xff0c;延迟输出用一个数字循环减实现

.ORIG x3000

; *** Begin user program code here ***
LOOP LEA R0, STUID ; 打印字符串1
PUTS ;TRAP x22
AND R0, R0, #0
LD R0, DELAY
SLEEP ADD R0, R0, #-1
BRp SLEEP

BRnzp LOOP
DELAY .FILL #25000
STUID .STRINGZ "JL22110003 "
; *** End user program code here ***
.END

中断服务例程如下&#xff0c;首先是获取输入的数字&#xff0c;使用GETC获取&#xff0c;ASCIIZ存储’0’的acsii码负值&#xff0c;ASCIIN存储’9’的acsii码负值&#xff0c;将获取的值与之相减&#xff0c;正确的数字ascii码应该在’0’-&#39;9’之间&#xff0c;如果不符合则跳转至ERROR&#xff0c;输出其不是十进制数并执行RTI返回用户程序&#xff0c;正确执行MAIN即汉诺塔递归部分

; *** Begin interrupt service routine code here ***
LD R6,STACK;压栈
LD R0, NEWLINE
OUT
;输入汉诺塔阶数
GETC ;input n
;从键盘读入n
OUT
ADD R5, R0, #0
LD R3, ASCIIZ
ADD R0, R0, R3 ;n-&#39;0&#39;
ADD R4, R0, #0
BRn ERROR
LD R3, ASCIIN
ADD R0, R5, R3 ;n-&#39;9&#39;
BRp ERROR
LEA R0, OUTPUT2
PUTS
LD R0, NEWLINE
OUT
ADD R0, R4, #0
BR MAIN
ERROR LEA R0, OUTPUT1
PUTS
FINISH LD R0, NEWLINE
OUT
RTI

以下是调用HANOI递归程序以及处理计算结果的部分代码&#xff0c;R6是栈指针&#xff0c;首先将正确处理后的n即R0压栈&#xff0c;作为HANOI的参数&#xff0c;经过HANOI递归后&#xff0c;结果会存储在R1中&#xff0c;随后输出字符串以及结果的acsii码&#xff0c;个十百位分别处理完后直接输出

MAIN ADD R6,R6,#-1
STR R0,R6,#0
JSR HANOI
;output
LEA R0,OUTPUT3
PUTS
LD R0, OFF
LD R2, NEGH
LOOPH ADD R1, R2, R1
BRn ENDH
ADD R0, R0, #1
BRnzp LOOPH
ENDH OUT ; 百位
LD R3, POSH
ADD R1, R1, R3
LD R0, OFF
LD R2, NEGS
LOOPS ADD R1, R2, R1
BRn ENDS
ADD R0, R0, #1
BRnzp LOOPS
ENDS OUT ; 十位
ADD R1, R1, #10
LD R0, OFF
ADD R0, R0, R1
OUT ; 个位
LEA R0,OUTPUT4
PUTS
HALT

以下是汉诺塔的递归部分程序&#xff0c;使用栈完成递归功能&#xff0c;计算递推式&#xff0c;联系到书本上斐波那契的递归计算过程&#xff0c;此过程与之十分相似&#xff0c;首先将调用者的返回地址压栈&#xff0c;再将参数压栈&#xff0c;最后压入一个参数用来检验n &#61; 0,1时的基本情况&#xff0c;如果计算到了基本情况&#xff0c;说明递归已到最大深度&#xff0c;此时跳转至DONE&#xff0c;否则还需要继续计算下一层n-1&#xff0c;使用R1寄存器保存H(n)计算结果&#xff0c;每次计算都是对其加上一定值&#xff0c;当递归完成后得到的结果就是保存在R1中的最终结果





H


(


0


)


&#61;


0



H


(


n


)


&#61;


2


H


(


n





1


)


&#43;


1



H(0) &#61; 0\\\\H(n) &#61; 2H(n-1) &#43; 1


H(0)&#61;0H(n)&#61;2H(n1)&#43;1

HANOI ADD R6, R6, #-1
STR R7, R6, #0 ; Push R7, the return linkage
ADD R6, R6, #-1
STR R0, R6, #0 ; Push R0, the value of n
ADD R6, R6, #-1
STR R2, R6, #0 ; Push R2, which is needed in the subroutine
; Check for base case
AND R2, R0, #-2
BRnp SKIP ; H(n)&#61;n if n&#61;0,1
ADD R1, R0, #0 ; R0&#61;n is the answer
BRnzp DONE
; Not a base case, do the recursion
SKIP ADD R0, R0, #-1 ; R0 &#61; n-1
JSR HANOI ; R1 &#61; H(n-1)
ADD R1, R1, R1; R1 &#61; 2H(n-1)
ADD R1, R1, #1 ; R1 &#61; 2H(n-1) &#43; 1
; Restore registers and return
DONE LDR R2, R6, #0
ADD R6, R6, #1
LDR R0, R6, #0
ADD R6, R6, #1
LDR R7, R6, #0
ADD R6, R6, #1
RET
;
ASCIIZ .FILL xFFD0
ASCIIN .FILL xFFC7
OFF .FILL x0030
STACK .FILL x6000
NEWLINE .FILL x000A
OUTPUT1 .STRINGZ " is not a decimal digit. "
OUTPUT2 .STRINGZ " is a decimal digit. "
OUTPUT3 .STRINGZ "Tower of hanoi needs "
OUTPUT4 .STRINGZ " moves."
NEGH .FILL xFF9C
POSH .FILL x0064
NEGS .FILL xFFF6

Result

Debug:

过程中遇到的主要问题有&#xff1a;
输出的结果不正确&#xff0c;有时出现输出乱码的情况&#xff0c;因此想到应该是acsii码处理有问题&#xff0c;所以检查发现在键盘读入时有问题

Test:
此处原本没有使用R5,R6寄存器保存R0的值&#xff0c;这样就会导致R0最后保存的值是n-&#39;0’处的值&#xff0c;从而出现错误&#xff0c;因此我在这里使用R5保存输入的n的初始的acsii码值&#xff0c;R4保存n的实际十进制值&#xff0c;R5用于后续判断是不是字母&#xff0c;而R4作为后面的HANOI的参数进行计算

在本地




LC3Tool



\\textLC3Tool


LC3Tool
调试完毕后&#xff0c;将代码整理如下&#xff1a;

; Unfortunately we have not YET installed Windows or Linux on the LC-3,
; so we are going to have to write some operating system code to enable
; keyboard interrupts. The OS code does three things:
;
; (1) Initializes the interrupt vector table with the starting
; address of the interrupt service routine. The keyboard
; interrupt vector is x80 and the interrupt vector table begins
; at memory location x0100. The keyboard interrupt service routine
; begins at x1000. Therefore, we must initialize memory location
; x0180 with the value x1000.
; (2) Sets bit 14 of the KBSR to enable interrupts.
; (3) Pushes a PSR and PC to the system stack so that it can jump
; to the user program at x3000 using an RTI instruction.
.ORIG x800
; (1) Initialize interrupt vector table.
LD R0, VEC
LD R1, ISR
STR R1, R0, #0
; (2) Set bit 14 of KBSR.
LDI R0, KBSR
LD R1, MASK
NOT R1, R1
AND R0, R0, R1
NOT R1, R1
ADD R0, R0, R1
STI R0, KBSR
; (3) Set up system stack to enter user space.
LD R0, PSR
ADD R6, R6, #-1
STR R0, R6, #0
LD R0, PC
ADD R6, R6, #-1
STR R0, R6, #0
; Enter user space.
RTI

VEC .FILL x0180
ISR .FILL x1000
KBSR .FILL xFE00
MASK .FILL x4000
PSR .FILL x8002
PC .FILL x3000
.END
.ORIG x3000

; *** Begin user program code here ***
LOOP LEA R0, STUID ; 打印字符串1
PUTS
AND R0, R0, #0
LD R0, DELAY
SLEEP ADD R0, R0, #-1
BRp SLEEP

BRnzp LOOP
DELAY .FILL #25000
STUID .STRINGZ "JL22110003 "
; *** End user program code here ***
.END
.ORIG x3FFF
; *** Begin honoi data here ***
HONOI_N .FILL xFFFF
; *** End honoi data here ***
.END
.ORIG x1000
; *** Begin interrupt service routine code here ***
LD R6,STACK;压栈
LD R0, NEWLINE
OUT
;输入汉诺塔阶数
GETC ;input n
;从键盘读入n
OUT
ADD R5, R0, #0
LD R3, ASCIIZ
ADD R0, R0, R3 ;n-&#39;0&#39;
ADD R4, R0, #0
BRn ERROR
LD R3, ASCIIN
ADD R0, R5, R3 ;n-&#39;9&#39;
BRp ERROR
LEA R0, OUTPUT2
PUTS
LD R0, NEWLINE
OUT
ADD R0, R4, #0
BR MAIN
ERROR LEA R0, OUTPUT1
PUTS
FINISH LD R0, NEWLINE
OUT
RTI

MAIN ADD R6,R6,#-1
STR R0,R6,#0
JSR HANOI
;output
LEA R0,OUTPUT3
PUTS
LD R0, OFF
LD R2, NEGH
LOOPH ADD R1, R2, R1
BRn ENDH
ADD R0, R0, #1
BRnzp LOOPH
ENDH OUT ; 百位
LD R3, POSH
ADD R1, R1, R3
LD R0, OFF
LD R2, NEGS
LOOPS ADD R1, R2, R1
BRn ENDS
ADD R0, R0, #1
BRnzp LOOPS
ENDS OUT ; 十位
ADD R1, R1, #10
LD R0, OFF
ADD R0, R0, R1
OUT ; 个位
LEA R0,OUTPUT4
PUTS
HALT
HANOI ADD R6, R6, #-1
STR R7, R6, #0 ; Push R7, the return linkage
ADD R6, R6, #-1
STR R0, R6, #0 ; Push R0, the value of n
ADD R6, R6, #-1
STR R2, R6, #0 ; Push R2, which is needed in the subroutine
; Check for base case
AND R2, R0, #-2
BRnp SKIP ; H(n)&#61;n if n&#61;0,1
ADD R1, R0, #0 ; R0&#61;n is the answer
BRnzp DONE
; Not a base case, do the recursion
SKIP ADD R0, R0, #-1 ; R0 &#61; n-1
JSR HANOI ; R1 &#61; H(n-1)
ADD R1, R1, R1; R1 &#61; 2H(n-1)
ADD R1, R1, #1 ; R1 &#61; 2H(n-1) &#43; 1
; Restore registers and return
DONE LDR R2, R6, #0
ADD R6, R6, #1
LDR R0, R6, #0
ADD R6, R6, #1
LDR R7, R6, #0
ADD R6, R6, #1
RET
;
ASCIIZ .FILL xFFD0
ASCIIN .FILL xFFC7
OFF .FILL x0030
STACK .FILL x6000
NEWLINE .FILL x000A
OUTPUT1 .STRINGZ " is not a decimal digit. "
OUTPUT2 .STRINGZ " is a decimal digit. "
OUTPUT3 .STRINGZ "Tower of hanoi needs "
OUTPUT4 .STRINGZ " moves."
NEGH .FILL xFF9C
POSH .FILL x0064
NEGS .FILL xFFF6
; *** End interrupt service routine code here ***
.END

输出结果如下&#xff0c;正常运行&#xff0c;输出正确。

测试用例主要对大小写字母都进行测试&#xff0c;而数字则对0-9均测试&#xff0c;输出均正确


推荐阅读
  • 1print过程procprint<data数据集名><选项>;*label指定打印输出标签noobs制定不显示观测序号*by变量名1< ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 使用圣杯布局模式实现网站首页的内容布局
    本文介绍了使用圣杯布局模式实现网站首页的内容布局的方法,包括HTML部分代码和实例。同时还提供了公司新闻、最新产品、关于我们、联系我们等页面的布局示例。商品展示区包括了车里子和农家生态土鸡蛋等产品的价格信息。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
  • 本文主要介绍了gym102222KVertex Covers(高维前缀和,meet in the middle)相关的知识,包括题意、思路和解题代码。题目给定一张n点m边的图,点带点权,定义点覆盖的权值为点权之积,要求所有点覆盖的权值之和膜qn小于等于36。文章详细介绍了解题思路,通过将图分成两个点数接近的点集L和R,并分别枚举子集S和T,判断S和T能否覆盖所有内部的边。文章还提到了使用位运算加速判断覆盖和推导T'的方法。最后给出了解题的代码。 ... [详细]
  • x86 linux的进程调度,x86体系结构下Linux2.6.26的进程调度和切换
    进程调度相关数据结构task_structtask_struct是进程在内核中对应的数据结构,它标识了进程的状态等各项信息。其中有一项thread_struct结构的 ... [详细]
  • 现在比较流行使用静态网站生成器来搭建网站,博客产品着陆页微信转发页面等。但每次都需要对服务器进行配置,也是一个重复但繁琐的工作。使用DockerWeb,只需5分钟就能搭建一个基于D ... [详细]
  • des算法php,Des算法属于加密技术中的
    本文目录一览:1、des是什么算法2、80分求 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
author-avatar
时光机少女
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有